#coding=utf-8
# Copyright (c) 2016 Tinydot. inc.
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import os
import yaml
from . import mlcfunctions as mlcfunctions
from collections import OrderedDict

from ml_feature.util.logger import getLogger
get_logger = getLogger

ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))
RESOURCE_DIR = os.path.abspath(os.path.join(ROOT_DIR, "resource"))
TENSORBOARD_DIR = os.path.abspath(os.path.join(RESOURCE_DIR, "tensorboard"))
CONFIG_DIR = os.path.abspath(os.path.join(ROOT_DIR, "config"))

APP_NAME = "ML Character"
VERSION  = (0,0,1)
AUTHOR   = "author"


def get_app_name():
    """
    获取工具信息
    :return:
    """
    return "%s:%s.%s.%s"%((APP_NAME,)+VERSION)

def bytes_to_human(s, factor = 1024, unint_str=["B", "KB", "MB", "GB", "TB", "PB"]):
    if type(s)==type(''):
        return s
    unint_str_clone = unint_str.copy()
    max_unit = unint_str_clone.pop()
    return _bytes_to_human(s,factor,unint_str_clone,max_unit)

def _bytes_to_human(s, factor = 1024, unit_str = ["B", "KB", "MB", "GB", "TB"], max_unit="PB"):
    """
    数据大小转换
    :param s: 无单位数据
    :return: 有单位数据
    """
    unit_size = 1
    for u in unit_str:
        if s < unit_size*factor:
            return "%.2f %s"%(s/(unit_size),u)
        unit_size *= factor
    return "%.2f %s"%(s/unit_size, max_unit)


__config = {}
def get_config(config_file=None):
    """
    获取配置文件内容，默认配置文件位置: ml_feature/config.yaml
    :param config_file: 配置文件
    :return: 配置文件内容，dict 类型
    """

    _config_file = config_file or os.path.join(CONFIG_DIR, "config.yaml")

    global  __config
    if (__config is not None) and (_config_file in __config):
        return __config[_config_file]

    assert os.path.isfile(_config_file)

    with open(_config_file, "rb") as f:
        __config[_config_file] = yaml.load(f)["ml_feature"]
        return __config[_config_file]


def get_config_json(json_file=None):
    """
    获取Op的特征配置文件内容，默认位置: ml_feature/operation.json
    :param json_file: Op配置文件路径
    :return: 配置文件内容，dict类型
    """
    import json
    _config_file = json_file or os.path.join(CONFIG_DIR, "operation.json")
    assert os.path.isfile(_config_file)
    with open(_config_file, "r") as f:
        data = json.load(f)
        if "__comment__" in data:
            del data["__comment__"]
    return data


def get_mlc_stream_encoder():
    """
    获取伪指令流输出方法，以及方法名称
    eg:
    f, n = get_mlc_stream_encoder()
    write_line(mlc_file, n)
    for op_feature in op_feature_list:
        write_line(f(op_feature))

    :return: encoder_func, encoder_name
    """
    stream_format = get_config().get("mlc_stream_format", None)

    ecds = mlcfunctions.mlc_encoders()
    assert stream_format in ecds, "config.mlc_stream_format(%s) should in %s"%(stream_format, [k for k in ecds])

    return ecds[stream_format], stream_format


def get_mlc_stream_list(encoder_name, mlc_text):
    """
    从伪指令文件流中解析出所有op的特征数组
    :param encoder_name: 伪指令流文件
    :param mlc_text: 伪指令流文件内容
    :return: op的特征数组
    """
    dcds = mlcfunctions.mlc_decoders()
    assert encoder_name in dcds, "decoder: %s not find in %s"%(encoder_name, [k for k in dcds])
    return dcds[encoder_name](mlc_text)


def get_config_view_show_features():
    """
    从配置文件中获取界面显示特征列表
    :return:
    """
    cfg = get_config()
    features = OrderedDict()

    for f in cfg.get("view_default_features",[]):
        features[f[0]] = {'col_name':f[1],'unit_str':f[2],'unit_int':f[3]}

    for f in cfg.get("view_shown_features", []):
        if f[0] not in features:
            features[f[0]] = {'col_name':f[1],'unit_str':f[2],'unit_int':f[3]}

    for f in cfg.get("view_hidden_features", []):
        if f in features:
            del features[f]

    return features

def get_config_view_hidden_ops():
    """
    从配置文件中获取不需要显示的Op
    :return:
    """
    cfg = get_config()
    return cfg.get("view_hidden_op", [])

def get_config_type_bytes():
    """
    从配置文件中获取各个属性的对应多少byte
    :return:
    """
    cfg = get_config()
    type_bytes_dict = dict()
    for t in cfg.get("type_bytes", []):
        type_bytes_dict[t[0]] = t[1]
    return type_bytes_dict

def get_config_mlc_feature():
    """
    从配置文件中获得需要在伪指令文件中生成的特征
    :return:
    """
    cfg = get_config()
    feature = OrderedDict()
    for f in cfg.get("mlc_stream_feature", []):
        feature[f[0]] = f[1]
    return feature